package git.soulbgm.utils;

import git.soulbgm.pojo.ValueUnit;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 存储单元转换
 *
 * @author SoulBGM
 * @date 2023-03-03
 */
public class StorageUnitConvert {

    private StorageUnitConvert() {}

    /**
     * 单位
     *
     * @author SoulBGM
     * @date 2023-03-03
     */
    public enum Unit {
        /**
         * 字节(B)
         */
        B("B"),
        /**
         * 千字节(KB)
         */
        KB("KB"),
        /**
         * 兆字节(MB)
         */
        MB("MB"),
        /**
         * 千兆字节(GB)
         */
        GB("GB"),
        /**
         * 太字节(TB)
         */
        TB("TB"),
        /**
         * 拍字节(PB)
         */
        PB("PB"),
        /**
         * 艾字节(EB)
         */
        EB("EB");

        private final String unit;

        Unit(String unit) {
            this.unit = unit;
        }

        public String getUnit() {
            return unit;
        }
    }

    /**
     * 单位
     */
    private static final Unit[] UNITS = new Unit[]{
            Unit.B, Unit.KB, Unit.MB, Unit.GB, Unit.TB, Unit.PB, Unit.EB
    };

    /**
     * 转换值
     */
    private static final BigDecimal CONVERSION_VALUE = new BigDecimal(1024);

    /**
     * 默认的精度
     */
    private static final int DEFAULT_SCALE = 3;

    /**
     * 将字节值动态转换
     *
     * @param byteValue 字节值
     * @return {@link ValueUnit}
     */
    public static ValueUnit convert(long byteValue) {
        return convert(new BigDecimal(byteValue), Unit.B, DEFAULT_SCALE);
    }

    /**
     * 将字节值转换为固定单位
     *
     * @param byteValue 字节值
     * @param fixedUnit 转换到的单位
     * @return {@link ValueUnit}
     */
    public static ValueUnit convertFixedUnit(long byteValue, Unit fixedUnit) {
        return convertFixedUnit(new BigDecimal(byteValue), Unit.B, fixedUnit, DEFAULT_SCALE);
    }

    /**
     * 转换
     *
     * @param val   值
     * @param unit  单位
     * @param scale 精度
     * @return {@link ValueUnit}
     */
    public static ValueUnit convert(BigDecimal val, Unit unit, int scale) {
        return convert(val, unit, UNITS[UNITS.length - 1], scale);
    }

    /**
     * 转换
     *
     * @param val     值
     * @param unit    单位
     * @param maxUnit 最高的单位
     * @param scale   精度
     * @return {@link ValueUnit}
     */
    public static ValueUnit convert(BigDecimal val, Unit unit, Unit maxUnit, int scale) {
        int maxIndex = getIndex(maxUnit);
        int index = getIndex(unit);
        double v = val.doubleValue();

        for (int i = 0; i < maxIndex; i++) {
            if (v > CONVERSION_VALUE.doubleValue()) {
                index++;
                v = new BigDecimal(v).divide(CONVERSION_VALUE, scale, RoundingMode.HALF_UP).doubleValue();
            } else {
                break;
            }
        }
        return new ValueUnit(v, UNITS[index].unit);
    }

    /**
     * 转换为固定单位
     *
     * @param val       值
     * @param unit      当前值的单位
     * @param fixedUnit 转换到的单位
     * @param scale     精度
     * @return {@link ValueUnit}
     */
    public static ValueUnit convertFixedUnit(BigDecimal val, Unit unit, Unit fixedUnit, int scale) {
        int fixedIndex = getIndex(fixedUnit);
        int index = getIndex(unit);
        double v = val.doubleValue();

        for (int i = 0; i < fixedIndex; i++) {
            index++;
            v = new BigDecimal(v).divide(CONVERSION_VALUE, scale, RoundingMode.HALF_UP).doubleValue();
        }
        return new ValueUnit(v, UNITS[index].unit);
    }

    /**
     * 获得下标
     *
     * @param unit 单位
     * @return int
     */
    private static int getIndex(Unit unit) {
        for (int i = 0; i < UNITS.length; i++) {
            if (UNITS[i] == unit) {
                return i;
            }
        }
        return -1;
    }

}
